from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer

from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.core.security import create_access_token, get_current_user

from app.schemas.user import UserCreate, UserResponse, Token, UserLogin, ChangePasswordRequest

from app.services.user_service import UserService
from app.services.email_service import EmailService

from datetime import timedelta

from app.core.config import settings

from app.models.user import User
from pydantic import BaseModel
import secrets

router = APIRouter()

class ResetPasswordRequest(BaseModel):
    email: str

class ResetPasswordConfirmRequest(BaseModel):
    token: str
    new_password: str

# response_model 就是 声明响应的类型，简单理解就是执行完函数后，返回的结果，需要和 UserResponse 类型一致
# 详细文档可以看：https://fastapi.tiangolo.com/tutorial/response-model/?h=
@router.post("/register", response_model=UserResponse)
# Depends(get_db) 表示 db 参数是一个依赖项，它会调用 get_db 函数来获取一个数据库会话（AsyncSession）。
# FastAPI 会在处理请求时自动执行 get_db 函数，并将返回的结果传递给 register 函数的 db 参数。
async def register(user_data: UserCreate, db: AsyncSession = Depends(get_db)): 
    try:
        user_service = UserService(db)
        user = await user_service.create_user(user_data)
        return user
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.post("/token", response_model=Token)
async def login(user_data: UserLogin, db: AsyncSession = Depends(get_db)):
    user_service = UserService(db)
    user = await user_service.authenticate_user(
        user_data.email, 
        user_data.password
    )
    if not user:
        raise HTTPException(
            status_code=401,
            detail="Incorrect email or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    access_token_expires = timedelta(
        minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES
    )
    access_token = create_access_token(
        data={"sub": user.email}, 
        expires_delta=access_token_expires
    )
    return {
        "access_token": access_token, 
        "token_type": "bearer"
    }


@router.get("/users/me", response_model=UserResponse)
async def get_current_user_info(
    current_user: User = Depends(get_current_user)
):
    """获取当前登录用户的信息"""
    return current_user


@router.put("/users/me/password")
async def change_password(
    password_data: ChangePasswordRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """修改当前用户密码"""
    try:
        user_service = UserService(db)
        success = await user_service.change_password(
            current_user.id, 
            password_data.current_password, 
            password_data.new_password
        )
        if success:
            return {"message": "密码修改成功"}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.post("/users/reset-password")
async def reset_password(request: ResetPasswordRequest, db: AsyncSession = Depends(get_db)):
    """重置密码接口"""
    try:
        # 验证邮箱是否存在
        user_service = UserService(db)
        user = await user_service.get_user_by_email(request.email)
        
        if not user:
            # 为了安全起见，即使邮箱不存在也返回成功信息
            return {"message": "如果该邮箱存在，密码重置邮件已发送"}
        
        # 生成重置令牌（简化实现，实际应存储在数据库或缓存中）
        reset_token = secrets.token_urlsafe(32)
        
        # 发送重置邮件
        email_sent = EmailService.send_password_reset_email(request.email, reset_token)
        
        if email_sent:
            return {"message": "如果该邮箱存在，密码重置邮件已发送"}
        else:
            raise HTTPException(status_code=500, detail="邮件发送失败")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/users/reset-password-confirm")
async def reset_password_confirm(request: ResetPasswordConfirmRequest, db: AsyncSession = Depends(get_db)):
    """确认重置密码接口"""
    try:
        # 在实际应用中，这里需要验证令牌的有效性
        # 简化实现，直接重置密码
        
        # 注意：这是一个简化的实现，实际应用中需要：
        # 1. 验证令牌是否存在且未过期
        # 2. 根据令牌找到对应的用户
        # 3. 更新用户密码
        # 4. 使令牌失效
        
        return {"message": "密码重置成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))